package com.tencent.wxcloudrun.frontcontroller;

import com.alibaba.fastjson.JSONObject;
import com.tencent.wxcloudrun.dto.Order;
import com.tencent.wxcloudrun.dto.Users;
import com.tencent.wxcloudrun.mapper.OrderMapper;
import com.tencent.wxcloudrun.mapper.UsersMapper;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.apache.commons.lang3.RandomStringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;


/**
 * @author lichongbing
 * @version 1.0.0
 * @createdate 2023/3/8 11:56
 * @description: TODO
 */
@RestController
@Api(tags = "商户直接支付模块")
@Slf4j
public class PayController {

    @Value("${wxpay.merchantId}")
    private String merchantId;
    @Value("${wxpay.privateKeyPath}")
    private String privateKeyPath;
    @Value("${wxpay.merchantSerialNumber}")
    private String merchantSerialNumber;
    @Value("${wxpay.apiV3key}")
    private String apiV3key;
    @Value("${wxpay.appid}")
    private String appid;
    public static Config config = null;



    public static JsapiServiceExtension service = null;

    public static RefundService refundService = null;

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private OrderMapper orderMapper;


    /**
     * 云托管支付
     * @param request
     * @param jsonObject
     * @return "body":"测试微信支付",
     * "total_fee":1,
     */
    @PostMapping(value = "/pay/placeOder")
    public Object placeOder(HttpServletRequest request, @RequestBody JSONObject jsonObject) throws IOException, InterruptedException {
        String spbill_create_ip = getIpAddr(request);
        String env_id = request.getHeader("x-wx-env");
        String service = request.getHeader("x-wx-service");
        JSONObject jsonObject1 = new JSONObject();
        Integer money = jsonObject.getInteger("money");
        jsonObject1.put("total_fee", money);
        jsonObject1.put("body", jsonObject.getString("remark"));
        jsonObject1.put("sub_mch_id", merchantId);
        String out_trade_no = getOutTradeNo();
        jsonObject1.put("out_trade_no", out_trade_no);
        String openid = request.getHeader("X-WX-OPENID");
        jsonObject1.put("openid", openid);
        jsonObject1.put("spbill_create_ip", spbill_create_ip);
        jsonObject1.put("env_id", env_id);
        jsonObject1.put("callback_type", 2);
        JSONObject container = new JSONObject();
        container.put("service", service);
        container.put("path", "/pay/callback");
        jsonObject1.put("container", container);
        String url = "https://api.weixin.qq.com/_/pay/unifiedorder";
        System.out.println(jsonObject1.toString());
        HttpRequest requests = HttpRequest.newBuilder()
                .uri(java.net.URI.create(url))
                .POST(HttpRequest.BodyPublishers.ofString(jsonObject1.toString()))
                .setHeader("Accept", "application/json")
                .setHeader("Content-Type", "application/json")
                .build();
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(5000))
                .build();
        HttpResponse response = client.send(requests, HttpResponse.BodyHandlers.ofString());
        Object body = response.body();
        System.out.println(body);
        return body;

    }


    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }




    /**
     * 生成商户订单号22位
     *
     * @return
     */
    public static String getOutTradeNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String date = sdf.format(new Date());
        String randomstring = RandomStringUtils.randomNumeric(8);
        return date + randomstring;
    }

    /**
     * 商户直连支付
     *
     * @return
     */
    @PostMapping(value = "/pay/placeOder1")
    public PrepayWithRequestPaymentResponse getString(HttpServletRequest requests, @RequestBody JSONObject jsonObject) {
        String openid = requests.getHeader("X-WX-OPENID");
        if (config == null){
            config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(merchantId)
                    .privateKeyFromPath(System.getProperty("user.dir") + privateKeyPath)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3key)
                    .build();
        }
        if(service==null){
            service = new JsapiServiceExtension.Builder().config(config).build();
        }
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        Integer money = jsonObject.getInteger("money");
        amount.setCurrency("CNY");
        amount.setTotal(money);
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(appid);
        request.setMchid(merchantId);
        request.setDescription(jsonObject.getString("remark"));
        request.setNotifyUrl("https://pay-33830-5-1302898718.sh.run.tcloudbase.com/pay/callback");
        String outTradeNo = getOutTradeNo();
        request.setOutTradeNo(outTradeNo);
        Payer payer = new Payer();
        payer.setOpenid(openid);
        request.setPayer(payer);
        PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = service.prepayWithRequestPayment(request);
        return prepayWithRequestPaymentResponse;
    }


    /**
     * 查询订单
     * @param jsonObject
     * @return
     */

    @PostMapping(value = "/pay/queryOrderById")
    public Transaction queryOrderById(@RequestBody JSONObject jsonObject) {
        QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
        queryRequest.setMchid(jsonObject.getString("mchid"));
        queryRequest.setTransactionId(jsonObject.getString("transactionId"));

        try {
            Transaction result = service.queryOrderById(queryRequest);
            log.info("result=[%s]\n", result);
            return result;
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            log.error("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            log.error("reponse body=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            return null;
        }
    }

    /**
     * 查询订单
     * @param jsonObject
     * @return
     */
    @PostMapping(value = "/pay/queryOrderByOutTradeNo")
    public String queryOrderByOutTradeNo(@RequestBody JSONObject jsonObject){
        QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new QueryOrderByOutTradeNoRequest();
        queryOrderByOutTradeNoRequest.setMchid(jsonObject.getString("mchid"));
        queryOrderByOutTradeNoRequest.setOutTradeNo(jsonObject.getString("outTradeNo"));
        try {
            Transaction result = service.queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);
            log.info("result=[%s]\n", result);
            return result.toString();
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            log.error("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            log.error("reponse body=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            return null;
        }
   }

    /**
     * 关闭订单
     * @param jsonObject
     * @return
     */
    @PostMapping(value = "/pay/closeOrder")
    public String closeOrder(@RequestBody JSONObject jsonObject){
        CloseOrderRequest closeOrderRequest = new CloseOrderRequest();
        closeOrderRequest.setMchid(jsonObject.getString("mchid"));
        closeOrderRequest.setOutTradeNo(jsonObject.getString("outTradeNo"));
        try {
            service.closeOrder(closeOrderRequest);
            return "关闭成功";
        } catch (ServiceException e) {
            log.error("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            log.error("reponse body=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            return null;
        }
    }
    /**
     * 申请退款
     * @param jsonObject
     * @return
     */
    @PostMapping(value = "/pay/refund")
    public Refund refund(@RequestBody JSONObject jsonObject){
        CreateRequest createRequest = new CreateRequest();
        createRequest.setSubMchid(jsonObject.getString("mchid"));
        createRequest.setOutTradeNo(jsonObject.getString("outTradeNo"));
        createRequest.setOutRefundNo(jsonObject.getString("outRefundNo"));
        createRequest.setNotifyUrl("https://pay-33830-5-1302898718.sh.run.tcloudbase.com/pay/refundCallback");
        AmountReq amount = new AmountReq();
        amount.setRefund(jsonObject.getLong("refund"));
        amount.setTotal(jsonObject.getLong("total"));
        amount.setCurrency("CNY");
        createRequest.setAmount(amount);
        try {
            Refund result = refundService.create(createRequest);
            log.info("result=[%s]\n", result);
            return result;
        } catch (ServiceException e) {
            log.error("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            log.error("reponse body=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            return null;
        }
    }

    /**
     * 查询退款
     * @param jsonObject
     * @return
     */
    @PostMapping(value = "/pay/queryRefund")
    public Refund queryByOutRefundNo(@RequestBody JSONObject jsonObject){
        QueryByOutRefundNoRequest queryRefundRequest = new QueryByOutRefundNoRequest();
        queryRefundRequest.setSubMchid(jsonObject.getString("mchid"));
        queryRefundRequest.setOutRefundNo(jsonObject.getString("outRefundNo"));
        try {
            Refund result = refundService.queryByOutRefundNo(queryRefundRequest);
            log.info("result=[%s]\n", result);
            return result;
        } catch (ServiceException e) {
            log.error("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            log.error("reponse body=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            return null;
        }
    }
    /**
     * 余额支付
     */
    @PostMapping(value = "/pay/balancePay")
    public JSONObject balancePay(HttpServletRequest requests,@RequestBody JSONObject jsonObject){
        String openid = jsonObject.getString("openid");
        String orderId = jsonObject.getString("orderId");
        Order order = orderMapper.orderDetail(orderId);
        Integer amountreal = order.getAmountreal();
        Users user = usersMapper.selectByOpenid(openid);
        Integer balance = user.getBalance();
        Integer newblance = balance - amountreal;
        usersMapper.updateUserBalance(openid,newblance);
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("code",0);
        jsonObject1.put("msg","支付成功");
        return jsonObject1;
    }



}
